#!/usr/bin/env python

# Copyright 2008 David Selby dave6502@googlemail.com

# This file is part of kmotion.

# kmotion is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# kmotion is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with kmotion.  If not, see <http://www.gnu.org/licenses/>.

"""
Exports various methods used to initialize core configuration
"""

import os, ConfigParser
from subprocess import * # breaking habit of a lifetime !
import sort_rc, logger, mutex

log_level = 'WARNING'
logger = logger.Logger('init_core', log_level)

HEADER_TEXT = """
##############################################################
# This config file has been automatically generated by kmotion
# from www_rc DO NOT CHANGE IT IN ANY WAY !!!
##############################################################
# User defined options
##############################################################
"""

COMPULSORY_TEXT = """
#############################################################
# Compulsory options
#############################################################
"""

THREAD_TEXT = """
#############################################################
# Threads
#############################################################
"""

CODE_TEXT = """#!/bin/bash

# Copyright 2008 David Selby dave6502@googlemail.com

# This file is part of kmotion.

# kmotion is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# kmotion is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with kmotion.  If not, see <http://www.gnu.org/licenses/>.
"""

    
def init_rcs(kmotion_dir, ramdisk_dir):
    """
    Init the rc's during an install
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              ramdisk_dir ... the 'root' directory of ramdisk
    excepts :
    return  : none
    """
    
    # set default images_dbase_dir in kmotion_rc
    logger.log('init_rcs() - Setting images_dbase_dir to \'%s/images_dbase\' in kmotion_rc' % kmotion_dir, 'DEBUG')
    
    parser = ConfigParser.SafeConfigParser()
    parser.read('%s/kmotion_rc' % kmotion_dir)
    parser.set('dirs', 'images_dbase_dir', '%s/images_dbase' % kmotion_dir)
    f_obj = open('%s/kmotion_rc' % kmotion_dir, 'w')
    parser.write(f_obj)
    f_obj.close()
    
    update_rcs(kmotion_dir, ramdisk_dir)

    
def update_rcs(kmotion_dir, ramdisk_dir):
    
    """
    Update the rc's during a 'kmotion' or 'kmotion reload'
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              ramdisk_dir ... the 'root' directory of ramdisk
    excepts :
    return  : none
    """
    
    # copy 'images_dbase_dir' from 'kmotion_rc' to 'www_rc' 
    logger.log('update_rcs() - Copy \'images_dbase_dir\' from \'kmotion_rc\' to \'www_rc\'', 'DEBUG')
    parser = ConfigParser.SafeConfigParser()
    parser.read('%s/kmotion_rc' % kmotion_dir)
    images_dbase_dir = parser.get('dirs', 'images_dbase_dir')
    parser = mutex_www_parser_rd(kmotion_dir)
    parser.set('system', 'images_dbase_dir', images_dbase_dir)
    mutex_www_parser_wr(kmotion_dir, parser)
        
    # set 'ramdisk_dir' in core_rc
    logger.log('update_rcs() - Setting ramdisk_dir to \'%s\' in core_rc' % ramdisk_dir, 'DEBUG')
    parser = mutex_core_parser_rd(kmotion_dir)
    parser.set('dirs', 'ramdisk_dir', ramdisk_dir )
    mutex_core_parser_wr(kmotion_dir, parser)
    
    # set the 'ramdisk_dir' in 'www_rc'
    logger.log('update_rcs() - Setting ramdisk_dir to \'%s\' in www_rc' % ramdisk_dir, 'DEBUG')
    parser = mutex_www_parser_rd(kmotion_dir)
    parser.set('system', 'ramdisk_dir', ramdisk_dir)
    mutex_www_parser_wr(kmotion_dir, parser)
    
    # copy 'version' from 'core_rc' to 'www_rc' 
    logger.log('update_rcs() - Copy \'version\' from \'core_rc\' to \'www_rc\'', 'DEBUG')
    parser = mutex_core_parser_rd(kmotion_dir)
    version = parser.get('version', 'string')
    parser = mutex_www_parser_rd(kmotion_dir)
    parser.set('system', 'version', version)
    parser.set('system', 'version_latest', version)
    mutex_www_parser_wr(kmotion_dir, parser)
    
    # Sets the 'func_f??_enabled' in 'www_rc' by scanning for valid files in 
    # the 'func' directory. Valid files have the format 'func<01-16>.sh'.
    logger.log('update_rcs() - Setting the \'func_f??_enabled\' in \'www_rc\'', 'DEBUG')
    parser = mutex_www_parser_rd(kmotion_dir)
    for func_num in range(1, 17):
        if os.path.isfile('%s/func/func%02i.sh' % (kmotion_dir, func_num)):
            parser.set('system', 'func_f%02i_enabled' % func_num, 'true')
        else:
            parser.set('system', 'func_f%02i_enabled' % func_num, 'false')
    mutex_www_parser_wr(kmotion_dir, parser)
    
    # copy 'msg' to 'www_rc' 
    logger.log('update_rcs() - Copy \'msg\' to \'www_rc\'', 'DEBUG') 
    # user generated file so error trap
    try:
        f_obj = open('../msg')
        msg = f_obj.read()
        f_obj.close()
    except IOError:
        msg = ''
        logger.log('update_rcs() - unable to read \'msg\'', 'DEBUG') 
        
    msg = msg.replace('\n', '<br>') 
    parser = mutex_www_parser_rd(kmotion_dir)
    parser.set('system', 'msg', msg)
    mutex_www_parser_wr(kmotion_dir, parser)
    
    sort_rc.sort_rc('%s/kmotion_rc' % kmotion_dir)
    try:
        mutex.acquire(kmotion_dir, 'www_rc') 
        sort_rc.sort_rc('%s/www/www_rc' % kmotion_dir) 
    finally:
        mutex.release(kmotion_dir, 'www_rc')
        
    try:
        mutex.acquire(kmotion_dir, 'core_rc') 
        sort_rc.sort_rc('%s/core/core_rc' % kmotion_dir)
    finally:
        mutex.release(kmotion_dir, 'core_rc')
       
  
def init_ramdisk_dir(kmotion_dir):
    """
    Init the ramdisk setting up the kmotion, events and tmp folders.
    Exception trap in case dir created between test and mkdirs.
    
    args    : ramdisk_dir ... the ramdisk dir, normally '/dev/shm'
    excepts :
    return  : none
    """
    
    parser = mutex_core_parser_rd(kmotion_dir)
    ramdisk_dir = parser.get('dirs', 'ramdisk_dir')
    
    if not os.path.isdir('%s/events' % ramdisk_dir): 
        try:
            os.makedirs('%s/events' % ramdisk_dir)
            logger.log('init_ramdisk_dir() - creating \'events\' folder', 'DEBUG')
        except OSError:
            pass
        
    for i in range(1, 17): # clear the events dir
        if os.path.isfile('%s/events/%s' % (ramdisk_dir, i)):
            try:
                os.remove('%s/events/%s' % (ramdisk_dir, i))
            except OSError:
                pass

    for i in range(1, 17):
        if not os.path.isdir('%s/%02i' % (ramdisk_dir, i)): 
            try:
                os.makedirs('%s/%02i' % (ramdisk_dir, i))
                logger.log('init_ramdisk_dir() - creating \'%02i\' folder' % i, 'DEBUG')
            except OSError:
                pass
            
    if not os.path.isdir('%s/tmp' % ramdisk_dir): 
        try:
            os.makedirs('%s/tmp' % ramdisk_dir)
            logger.log('init_ramdisk_dir() - creating \'tmp\' folder', 'DEBUG')
        except OSError:
            pass   
            
            
def init_motion_out(kmotion_dir):
    """
    Wipes the 'motion_output' file in preperation for new output.
    
    args    : kmotion_dir ... the 'root' directory of kmotion
    excepts :
    return  : none
    """      
          
    f_obj = open('%s/www/motion_out' % kmotion_dir, 'w') 
    f_obj.seek(0)
    f_obj.close()
  
    
def set_uid_gid_mutex(kmotion_dir, uid, gid):
    """
    Set the 'mutex', 'logs', 'www_rc', 'core_rc' and 'servo_state' directories 
    with the appropreate 'uid' and 'gid'to allow the apache2 user to have write 
    access.
    
    args    : kmotion_dir ... the 'root' directory of kmotion 
              uid ...         the user id
              gid ...         the group id of apache2
    excepts : 
    return  : none
    """
    
    mutex_ =      '%s/www/mutex' % kmotion_dir
    logs =        '%s/logs' % mutex_
    www_rc =      '%s/www_rc' % mutex_
    core_rc =     '%s/core_rc' % mutex_
    
    os.chown(mutex_, uid, gid)
    os.chmod(mutex_, 0770)
    os.chown(logs, uid, gid)
    os.chmod(logs, 0770)
    os.chown(www_rc, uid, gid)
    os.chmod(www_rc, 0770)
    os.chown(core_rc, uid, gid)
    os.chmod(core_rc, 0770)
    

def set_uid_gid_named_pipes(kmotion_dir, uid, gid):
    """
    Generate named pipes for function, settings and ptz communications with the 
    appropreate 'uid' and 'gid'. The 'uid' and 'gid' are set to allow the 
    apache2 user to write to these files.
    
    args    : kmotion_dir ... the 'root' directory of kmotion 
              uid ...         the user id
              gid ...         the group id of apache2
    excepts : 
    return  : none
    """
    
    # use BASH rather than os.mkfifo(), FIFO bug workaround :)
    fifo_func = '%s/www/fifo_func' % kmotion_dir
    if not os.path.exists(fifo_func):
        # os.mkfifo(fifo_func)
        call(['mkfifo', fifo_func])
    os.chown(fifo_func, uid, gid)
    os.chmod(fifo_func, 0660)
    
    fifo_settings = '%s/www/fifo_settings_wr' % kmotion_dir
    if not os.path.exists(fifo_settings):
        # os.mkfifo(fifo_settings)
        call(['mkfifo', fifo_settings])
    os.chown(fifo_settings, uid, gid)
    os.chmod(fifo_settings, 0660)
    
    fifo_ptz = '%s/www/fifo_ptz' % kmotion_dir
    if not os.path.exists(fifo_ptz):
        #os.mkfifo(fifo_ptz)
        call(['mkfifo', fifo_ptz])
    os.chown(fifo_ptz, uid, gid)
    os.chmod(fifo_ptz, 0660)

    fifo_ptz_preset = '%s/www/fifo_ptz_preset' % kmotion_dir
    if not os.path.exists(fifo_ptz_preset):
        #os.mkfifo(fifo_ptz_preset)
        call(['mkfifo', fifo_ptz_preset])
    os.chown(fifo_ptz_preset, uid, gid)
    os.chmod(fifo_ptz_preset, 0660)
    
    
def set_uid_gid_servo_state(kmotion_dir, uid, gid):
    """
    Generate 'servo_state' file with the appropreate 'uid' and 'gid'. 
    Called by 'install' and 'core_setup' the 'uid' and 'gid' are set to allow 
    the apache2 user to read these files.
    
    args    : kmotion_dir ... the 'root' directory of kmotion 
              uid ...         the user id
              gid ...         the group id of apache2
    excepts : 
    return  : none
    """
    
    servo_state = '%s/www/servo_state' % kmotion_dir
    os.chown(servo_state, uid, gid)
    os.chmod(servo_state, 0640)  

    
def gen_vhost(kmotion_dir):
    """
    Generate the kmotion vhost file from vhost_template expanding %directory%
    strings to their full paths as defined in kmotion_rc
        
    args    : kmotion_dir ... the 'root' directory of kmotion
    excepts : exit        ... if kmotion_rc cannot be read
    return  : none
    """
    
    logger.log('gen_vhost() - Generating vhost/kmotion file', 'DEBUG')
    
    parser = ConfigParser.SafeConfigParser()
    parser.read('%s/kmotion_rc' % kmotion_dir)
    images_dbase_dir = parser.get('dirs', 'images_dbase_dir')
    port = parser.get('misc', 'port')
    LDAP_enabled = parser.get('LDAP', 'enabled') in ['true', 'True',  'yes',  'Yes']
    LDAP_url = parser.get('LDAP', 'AuthLDAPUrl')
    parser = mutex_core_parser_rd(kmotion_dir)
    ramdisk_dir = parser.get('dirs', 'ramdisk_dir')
    
    if LDAP_enabled:
        logger.log('gen_vhost() - LDAP mode enabled', 'DEBUG')
        LDAP_block = """
        # ** INFORMATION ** LDAP mode enabled ... 
        AuthName "LDAP"
        AuthBasicProvider ldap
        AuthzLDAPAuthoritative off
        AuthLDAPUrl %s\n""" % LDAP_url
    else:
        logger.log('gen_vhost() - users_digest mode enabled', 'DEBUG')
        LDAP_block = """
        # ** INFORMATION ** Users digest file enabled ...
        AuthName "kmotion"
        AuthUserFile %s/www/passwords/users_digest\n""" % kmotion_dir
    
    f_obj1 = open('%s/www/vhosts/kmotion' % kmotion_dir, 'w')
    f_obj2 = open('%s/www/templates/vhosts_template' % kmotion_dir)
    lines = f_obj2.readlines()
    f_obj2.close()
    
    for i in range(len(lines)):
        lines[i] = lines[i].replace('%images_dbase_dir%', images_dbase_dir)
        lines[i] = lines[i].replace('%ramdisk_dir%', ramdisk_dir)
        lines[i] = lines[i].replace('%www_dir%', '%s/www/www' % kmotion_dir)
        lines[i] = lines[i].replace('%cgi_bin_dir%', '%s/www/www/cgi_bin' % kmotion_dir)
        lines[i] = lines[i].replace('%logs_dir%', '%s/www/apache_logs' % kmotion_dir)
        lines[i] = lines[i].replace('%port%', port)
        lines[i] = lines[i].replace('%LDAP_block%',  LDAP_block)
        f_obj1.write(lines[i])
    f_obj1.close()
        
      
def gen_kmotion(kmotion_dir, uid, gid):
    """
    Generates a kmotion executable which starts the kmotion daemons, executable 
    from anywhere in the system
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              uid ...         the uid for kmotion  
              gid ...         the gid for kmotion  
    excepts : 
    return  : none
    """
    
    code = CODE_TEXT + """
# Starts/stop/reloads the kmotion daemons, executable from anywhere in the system
# kmotion start|stop|reload

if [[ $UID = 0 ]]; then
    echo -e '\\nkmotion cant be run as root\\n'
    exit 0
fi

if [[ $1 != 'start' && $1 != 'stop' && $1 != 'restart' ]]; then
    echo -e '\\nkmotion start|stop|restart\\n'
    exit 0
fi

if [[ ! -z $2 ]]; then
    echo -e '\\nkmotion start|stop|restart\\n'
    exit 0
fi

cd %s/core
./kmotion.py $1

""" % kmotion_dir
    
    logger.log('gen_kmotion() - Generating \'kmotion\' exe', 'DEBUG')
        
    f_obj = open('%s/kmotion' % kmotion_dir, 'w')
    print >> f_obj, code
    f_obj.close()    

    os.chmod('%s/kmotion' % kmotion_dir, 0755)
    os.chown('%s/kmotion' % kmotion_dir, uid, gid)
    
      
def gen_kmotion_ptz(kmotion_dir, uid, gid):
    """
    Generates a kmotion_ptz executable which activates a ptz preset, 
    executable from anywhere in the system
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              uid ...         the uid for kmotion  
              gid ...         the gid for kmotion      
    excepts : 
    return  : none
    """
    
    code = CODE_TEXT + """
# Activates a ptz preset, executable from anywhere in the system
# kmotion_ptz <feed 1...16> <preset 1...4>

if [[ $UID = 0 ]]; then
    echo -e '\\nkmotion_ptz cant be run as root\\n'
    exit 0
fi

if [[ $1 = '-h' || $1 = '--help' ]]; then
    echo -e '\\nkmotion_ptz <feed 1..16> <preset 1..4>\\n'
    exit 0
fi

if [ -z $2 ]; then
    echo -e '\\nkmotion_ptz - to few parameters'
    echo -e 'kmotion_ptz <feed 1..16> <preset 1..4>\\n'
    exit 0
fi

if [ ! -z $3 ]; then
    echo -e '\\nkmotion_ptz - to many parameters'
    echo -e 'kmotion_ptz <feed 1..16> <preset 1..4>\\n'
    exit 0
fi

if [[ $1 -lt 1 || $1 -gt 16 || $2 -lt 1 || $2 -gt 4 ]]; then
    echo -e '\\nkmotion_ptz - parameters out of range\\n'
    exit 0
fi
    
cd %s/core
./kmotion_ptz.py $1 $2

""" % kmotion_dir
        
    logger.log('gen_kmotion_ptz() - Generating \'kmotion_ptz\' exe', 'DEBUG')
    
    f_obj = open('%s/kmotion_ptz' % kmotion_dir, 'w')
    print >> f_obj, code
    f_obj.close()    

    os.chmod('%s/kmotion_ptz' % kmotion_dir, 0755)
    os.chown('%s/kmotion_ptz' % kmotion_dir, uid, gid)
    
    
def mutex_www_parser_rd(kmotion_dir):
    """
    Safely generate a parser instance and under mutex control read 'www_rc'
    returning the parser instance.
    
    args    : kmotion_dir ... the 'root' directory of kmotion   
    excepts : 
    return  : parser ... a parser instance
    """
    
    parser = ConfigParser.SafeConfigParser()
    try:
        mutex.acquire(kmotion_dir, 'www_rc')
        parser.read('%s/www/www_rc' % kmotion_dir)
    finally:
        mutex.release(kmotion_dir, 'www_rc')
    return parser


def mutex_www_parser_wr(kmotion_dir, parser):
    """
    Safely write a parser instance to 'www_rc' under mutex control.
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              parser      ... the parser instance 
    excepts : 
    return  : 
    """

    try:
        mutex.acquire(kmotion_dir, 'www_rc')
        f_obj = open('%s/www/www_rc' % kmotion_dir, 'w')
        parser.write(f_obj)
        f_obj.close()
    finally:
        mutex.release(kmotion_dir, 'www_rc')


def mutex_core_parser_rd(kmotion_dir):
    """
    Safely generate a parser instance and under mutex control read 'core_rc'
    returning the parser instance.
    
    args    : kmotion_dir ... the 'root' directory of kmotion   
    excepts : 
    return  : parser ... a parser instance
    """
    
    parser = ConfigParser.SafeConfigParser()
    try:
        mutex.acquire(kmotion_dir, 'core_rc')
        parser.read('%s/core/core_rc' % kmotion_dir)
    finally:
        mutex.release(kmotion_dir, 'core_rc')
    return parser


def mutex_core_parser_wr(kmotion_dir, parser):
    """
    Safely write a parser instance to 'core_rc' under mutex control.
    
    args    : kmotion_dir ... the 'root' directory of kmotion
              parser      ... the parser instance 
    excepts : 
    return  : 
    """

    try:
        mutex.acquire(kmotion_dir, 'core_rc')
        f_obj = open('%s/core/core_rc' % kmotion_dir, 'w')
        parser.write(f_obj)
        f_obj.close()
    finally:
        mutex.release(kmotion_dir, 'core_rc')

    
    
    
    
    